<?php

namespace my;

class JElasticV2
{

    private $host;
    private $username;
    private $password;
    private $authorization;

    public function __construct()
    {
        $this->host = 'http://127.0.0.1:9200/';
        $this->username = env('ES_USERNAME');
        $this->password = env('ES_PASSWORD');
        $this->authorization = 'Authorization: Basic ' . base64_encode("$this->username:$this->password");
    }

    /**
     * 搜索文档，query是查询条件
     */
    public function search($index, $query = [], $field = [], $from = 0, $size = 20)
    {
        $post_data = [
            'from' => $from,
            'size' => $size,
            '_source' => $field,
        ];
        if (!empty($query)) {
            $post_data['query'] = $query;
        }
        $url = $this->host . $index . "/_search";
        return $this->curl_post($url, $post_data);
    }

    /**
     * 查找一个文档
     * @param $index
     * @param $doc_id
     * @return mixed $res['found'] true | false
     */
    public function findDoc($index, $doc_id)
    {
        $url = $this->host . $index . '/_doc/' . $doc_id;
        return $this->curl_get($url);
    }

    /**
     * 删除一个文档
     * @param $index
     * @param $doc_id
     * @return bool
     */
    public function deleteDoc($index, $doc_id)
    {
        $url = $this->host . $index . '/_doc/' . $doc_id;
        $res = $this->curl_delete($url);
        if ($res['result'] === 'deleted' || $res['result'] === 'not_found') {
            return true;
        } else {
//            pp($res);
            return false;
        }
    }

    /**
     * 获取多个文档;
     * @param $index
     * @param $doc_id_array
     * @return mixed $res['docs'][0]['found'] 为 true 则有数据 false 未找到
     */
    public function MGetDoc($index, $doc_id_array = [])
    {
        $url = $this->host . $index . '/_mget';
        $docs = [];
        foreach ($doc_id_array as $doc_id) {
            $docs[] = ['_id' => $doc_id];
        }
        $body = [
            'docs' => $docs
        ];
        if (empty($doc_id_array)) {
            return ['docs' => [['found' => false]]];
        }
        return $this->curl_post($url, $body);
    }

    /**
     * 添加、更新文档
     * @param $index
     * @param $body
     * @return mixed $res['result']  created updated
     */
    public function setDoc($index, $body = [])
    {
        if (empty($body['id'])) {
            trigger_error("文档必须包含id", E_USER_ERROR);
        }
        $doc_id = $body['id'];
        $url = $this->host . $index . '/_doc/' . $doc_id;
        return $this->curl_post($url, $body);
    }

    /**
     * 创建一个索引(表结构)
     * @param $index
     * @return mixed $res['acknowledged'] true
     */
    public function createIndex($index, $properties)
    {
        $url = $this->host . $index;
        $data = [
            'mappings' => [
                'properties' => $properties
            ],
            'settings' => [
                'number_of_shards' => 1,
                'number_of_replicas' => 0
            ]
        ];
        return $this->curl_put($url, $data);
    }

    /**
     * 获取索引信息
     * @param $index
     * @return false|mixed
     */
    public function getIndex($index)
    {
        $url = $this->host . $index;
        $res = $this->curl_get($url);
        if (isset($res['status']) && $res['status'] === 404) {
            return false;
        } else {
            return $res;
        }
    }

    /**
     * 删除一个索引
     * @param $index
     * @return bool
     */
    public function deleteIndex($index)
    {
        $url = $this->host . $index;
        $res = $this->curl_delete($url);
        if ((isset($res['status']) && $res['status'] === 404) || (isset($res['acknowledged']) && $res['acknowledged'] === true)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 删除全部索引
     * @return bool
     */
    public function deleteAllIndex()
    {
        $url = $this->host . '_all';
        $result = $this->curl_delete($url);
        if (isset($result['acknowledged']) && $result['acknowledged'] === true) {
            return true;
        } else {
            return false;
        }
    }
    /** todo 修改索引映射; 暂不需要 */

    /**
     * 批量生成文档
     * @param $index
     * @param $list
     * @return bool
     */
    public function setDocMulti($index, $list)
    {
        if (empty($list)) {
            return false;
        }
        $url = $this->host . $index . '/_bulk';
        $requestBody = "";
        foreach ($list as $doc) {
            $requestBody .= json_encode(['index' => ['_id' => $doc['id']]]) . "\n";
            $requestBody .= json_encode($doc) . "\n";
        }
        $result = $this->curl_post($url, $requestBody, [], false);
        if (isset($result['errors']) && $result['errors'] === false) {
            return true;
        } else {
            return false;
        }
    }

    /*----- 索引结构管理 -----*/

    /**
     * 查看索引结构
     * @param $index
     * @return mixed
     */
    public function getMapping($index)
    {
        $url = $this->host . $index . "/_mapping";
        return $this->curl_get($url);
    }

    /**
     * 查看分词情况
     * @param $index
     * @param $body ['analyzer' => 'keyword','text' => '周树人']
     * @return mixed
     */
    public function analyze($index, $body)
    {
        $url = $this->host . $index . "/_analyze";
        return $this->curl_post($url, $body);
    }


    /*----- 用户角色管理 -----*/

    /**
     * 获取全部用户
     */
    public function getAllUser()
    {
        $url = $this->host . "_security/user";
        return $this->curl_get($url);
    }

    /**
     * 获取全部角色
     */
    public function getRoles()
    {
        $url = $this->host . "_security/role";
        return $this->curl_get($url);
    }

    /**
     * 创建新用户, 修改用户都在这里; 密码不能小于6位
     * @param $body ['username' => 'your_username', 'password' => 'your_pwd', 'roles' => ['role1','role2']]
     * @return mixed
     */
    public function createUser($body)
    {
        if (empty($body['username'])) {
            trigger_error("username is empty", E_USER_ERROR);
        }
        $url = $this->host . "_security/user/" . $body['username'];
        return $this->curl_post($url, $body);
    }

    /**
     * 处理API返回数据
     * @param $result
     * @param $type
     * @return mixed|void
     */
    private function result_parse($result, $type = '')
    {
        if (isset($result['error'])) {
//            mylog('JElasticV2',var_export($result,true),'JElasticV2.log');
            trigger_error($result['error']['reason'], E_USER_ERROR);
        } else {
            if ($type === 'search') {
                return $result['hits']['hits'];
            } else {
                return $result;
            }
        }
    }


    /**  POST PUT GET DELETE */

    private function curl_post($url, $post_data, $headers = [], $json = true)
    {
        $headers[] = 'Content-Type: application/json';
        $headers[] = $this->authorization;
        if ($json) {
            $post_data = json_encode($post_data);
        }
        $json = $this->curl_request($url, 'POST', $post_data, $headers);
        return json_decode($json, true);
    }

    private function curl_put($url, $post_data)
    {
        $headers[] = 'Content-Type: application/json';
        $headers[] = $this->authorization;
        $post_data = json_encode($post_data);
        $json = $this->curl_request($url, 'PUT', $post_data, $headers);
        return json_decode($json, true);
    }

    private function curl_get($url)
    {
        $headers[] = $this->authorization;
        $json = $this->curl_request($url, 'GET', [], $headers);
        return json_decode($json, true);
    }

    private function curl_delete($url)
    {
        $headers[] = $this->authorization;
        $response = $this->curl_request($url, 'DELETE', [], $headers);
        return json_decode($response, true);
    }

    private function curl_request($url, $method = "POST", $param = [], $headers = [])
    {
        $ch = curl_init();
        if ($method === 'POST' || $method === 'PUT') {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
        }
        if ($method === 'GET') {
            $querystring = http_build_query($param);
            $url = $url . '?' . $querystring;
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }


}